package com.jungle.bfi.service.metadata.impl;

import com.jungle.base.dao.SpecBuilder;
import com.jungle.base.domain.bo.BaseUserBo;
import com.jungle.base.service.AbstractService;
import com.jungle.bfi.domain.bo.ApiPathBo;
import com.jungle.bfi.entity.ApiPathPo;
import com.jungle.bfi.metadata.swagger.enums.PathType;
import com.jungle.bfi.service.metadata.ApiPathService;
import lombok.extern.slf4j.Slf4j;
import org.n3r.idworker.Sid;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service(value = "apiPathService")
public class ApiPathServiceImpl extends AbstractService<ApiPathPo, ApiPathBo, String> implements ApiPathService {

    protected String getBoId(ApiPathBo bo) {
        if (bo.getId() == null) {
            Specification<ApiPathPo> spec =
                    PathType.SYSTEM.name().equals(bo.getType())||PathType.MODULE.name().equals(bo.getType())  ? toTitleSpec(bo) :
                            /*VirtualPath.SYSTEM.value().equals(bo.getPath()) ? new SpecBuilder<ApiPathPo>(bo).or(bo.toSummarySpec()).toSpec() : */new SpecBuilder<ApiPathPo>(bo).toSpec();
            List<ApiPathPo> list = this.findAll(spec);
            if (!list.isEmpty()) {
                String oldId = list.get(0).getId();
                bo.setId(oldId);
            }
        }
        return bo.getId();
    }
    private Specification<ApiPathPo> toTitleSpec(ApiPathBo bo) {
        return ((root, query, cb) -> cb.and(
                cb.equal(root.get("apiId"), bo.getApiId()),
                cb.equal(root.get("title"), bo.getTitle()))
        );
    }

    protected String newPoId() {
        return Sid.nextShort();
    }


    /**
     * Creates a consumer function for updating the business tree persistence object.
     * This method aims to map a business tree business object (BizTreeBo) to a persistence object (BizTreePo)
     * to perform an update operation.
     *
     * @param bo     The business tree business object containing the information to be updated.
     * @param userBo The current user's business object. Although not used in this code snippet,
     *               it might be used in the context for permission checks or auditing.
     */
    protected void updatePo(ApiPathBo bo, BaseUserBo userBo, ApiPathPo po) {

        // Map the business object to the persistent object
        mapper.map(bo, po);

        // Check if the sort values of the business object and the persistent object are different
        /*if (bo.getSort() != po.getSort()) {
            // Get the previous tree node with a sort value less than the current business object's sort value
            ApiPathPo prevTree = getPreviousTreeBySort(bo);

            // If no previous node is found or the previous node's sort value is null
            if (prevTree == null) {
                // Set the sort value of the persistent object to half of the business object's sort value
                po.setSort(bo.getSort() / 2);
            } else if (prevTree.getSort() == bo.getSort()) {
                // If the previous node's sort value is the same as the business object's sort value
                // Set the sort value of the persistent object to the previous node's sort value plus ten
                po.setSort(prevTree.getSort() + 10);
            } else {
                // If the previous node's sort value is between the current business object's sort value and the previous node's sort value
                // Set the sort value of the persistent object to the middle value between the previous node's sort value and the business object's sort value
                po.setSort(prevTree.getSort() + (bo.getSort() - prevTree.getSort()) / 2);
            }
        }*/
    }

    private ApiPathPo getPreviousTreeBySort(ApiPathBo bo) {
        Specification<ApiPathPo> spec = (root, query, cb) -> cb.and(cb.equal(root.get("parentId"), bo.getParentId()), cb.lessThan(root.get("sort"), bo.getSort()));
        return repository.findOne(spec, Sort.by(Sort.Direction.DESC, "sort"));
    }

    /**
     * Creates a persistence object (BizTreePo) from a business object (BizTreeBo).
     * This method is used to create a new persistence object from a business object,
     * typically during the creation of a new entity.
     *
     * @param bo     The business object containing the information to be mapped to the persistence object.
     * @param userBo The current user's business object. Although not used in this code snippet,
     *               it might be used in the context for permission checks or auditing.
     * @return A new instance of BizTreePo that has been mapped from the business object.
     **/
    protected ApiPathPo createPo(ApiPathBo bo, BaseUserBo userBo) {
        // Create a new instance of BizTreePo and map the business object to it using Dozer
        return mapper.map(bo, ApiPathPo.class);
    }


}
